package br.com.fiap.trabalho.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;

import br.com.fiap.trabalho.entity.Actor;
import br.com.fiap.trabalho.entity.Category;
import br.com.fiap.trabalho.entity.Movie;
import br.com.fiap.trabalho.entity.Studio;

public class JPAMovieDAO implements MovieDAO{
	
	public JPAMovieDAO() {
		createEntityManager();
	}

	private EntityManager em;
	
	private void createEntityManager() {
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistenceUnit"); 
		em = emf.createEntityManager(); 
	}

	// 5 min
	public Movie createMovie(Movie movie) {
		
		try{
			
			em.getTransaction().begin();
			em.persist(movie);
			em.getTransaction().commit();
		}
		catch(Exception e){
			e.printStackTrace();
			movie = null;
		}
		
		return movie;
	}

	// 5 min
	public boolean deleteMovie(Movie movie) {
		boolean verifica = true;
	
		movie = this.findMovie(movie.getId());
		if (movie == null) {
			verifica = false;
		}
		em.getTransaction().begin();
		em.remove(movie);
		em.getTransaction().commit();
		
		return verifica;
	}

	//10 min
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<Movie> selectMovieByTitle(String title) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Movie> c = cb.createQuery(Movie.class);
        Root<Movie> movie = c.from(Movie.class);
        c.where(cb.equal(movie.get("title"), cb.parameter(String.class, "title")));

        TypedQuery q = em.createQuery(c);
        q.setParameter("title", title);
       

        return (List<Movie>) q.getResultList();
	}

	// 7 min
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public List<Movie> selectMovieByYear(int year) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Movie> c = cb.createQuery(Movie.class);
        Root<Movie> movie = c.from(Movie.class);
        c.where(cb.equal(movie.get("year"), cb.parameter(Integer.class, "year")));

        TypedQuery q = em.createQuery(c);
        q.setParameter("year", year);

        return (List<Movie>) q.getResultList();
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<Movie> selectMoviesByActorName(String actorName) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
	    CriteriaQuery<Movie> c = cb.createQuery(Movie.class);
	    Root<Movie> movie = c.from(Movie.class);

		Join<Movie, Actor> actor = movie.join("actor");

		c.distinct(true).where(cb.equal(actor.get("fullName"), cb.parameter(String.class, "fullName")));

		TypedQuery q = em.createQuery(c);
		q.setParameter("fullName", actorName);

		return q.getResultList();
	}

	// 5 min
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<Movie> selectMovieByCategoryName(String categoryName) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Movie> c = cb.createQuery(Movie.class);
		Root<Movie> movie = c.from(Movie.class);

		Join<Movie, Category> category = movie.join("category");

		c.distinct(true).where(cb.equal(category.get("name"), cb.parameter(String.class, "name")));

		TypedQuery q = em.createQuery(c);
		q.setParameter("name", categoryName);

		return q.getResultList();
	}

	// 10 min
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<Movie> selectMovieByStudioName(String studioName) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Movie> c = cb.createQuery(Movie.class);
		Root<Movie> movie = c.from(Movie.class);

		Join<Movie, Studio> studio = movie.join("studio");

		c.distinct(true).where(cb.equal(studio.get("name"), cb.parameter(String.class, "name")));

		TypedQuery q = em.createQuery(c);
		q.setParameter("name", studioName);

		return q.getResultList();
	}
	
	private Movie findMovie(int id){ 
		return em.find(Movie.class, id); 
	} 

}
